/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package towerdefence.view;

import com.sun.opengl.util.texture.Texture;
import java.awt.Color;
import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import net.phys2d.math.Vector2f;
import towerdefence.controller.Controller;
import towerdefence.model.Block;
import towerdefence.model.Builder;
import towerdefence.model.Model;
import towerdefence.model.Player;
import towerdefence.view.GLCamera;
import static javax.media.opengl.GL.*;

/**
 *
 * @author Andreas
 */
public class GLCore extends GLCanvas implements GLEventListener {

    private Model model;
    private ArrayList<Controller> controllers = new ArrayList<Controller>();
    private Map<Integer, Texture> textureMap = new HashMap<Integer, Texture>();
    private GLCamera camera = new GLCamera(this);
    
    
    public GLCore(Model model) {
        this.model = model;
        setPreferredSize(new Dimension(800, 600));
        addGLEventListener(this);
        model.addStepListener(camera);
        camera.setPosition(new Vector2f(getPreferredSize().width / 2, getPreferredSize().height / 2));
    }

    @Override
    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();
        gl.setSwapInterval(1);
        gl.glMatrixMode(GL_MODELVIEW);
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

        gl.glLineWidth(2.0f);
        gl.glEnable(GL_LINE_SMOOTH);
        gl.glEnable(GL_POINT_SMOOTH);
        //gl.glEnable(GL_POLYGON_SMOOTH);
       // gl.glEnable(GL_COLOR_MATERIAL);
        gl.glEnable(GL_BLEND);
        //gl.glEnable(GL_DEPTH_TEST);
        //gl.glDepthFunc(GL_LEQUAL);
        gl.glShadeModel(GL_SMOOTH);
        gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        //gl.glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
        gl.glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
        gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
        try {
            TextureHandler.loadTextures();
        } catch (IOException ex) {
            Logger.getLogger(GLCore.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public GLCamera getCamera() {
        return camera;
    }
    
    

    @Override
    public void display(GLAutoDrawable drawable) {
        model.doStep(); // must be done here since the simulation step begins here. (FPSAnimator calls display())

        GL gl = drawable.getGL();
        gl.glLoadIdentity();
        gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        float zoom = camera.getZoom();
        gl.glScalef(zoom, zoom, zoom);
        
        GLBackgroundRenderer.drawBackground(gl, model.getLevel().getGroundControlPoints(), getWidth(), getHeight());

        for (Player player : model.getPlayers()) {
            for (Builder builder : player.getBuilders()) {
                GLBuilderRenderer.drawBuilder(gl, builder, Color.RED);
            }

            for (Block block : player.getBlocks()) {
                GLBlockRenderer.drawBlock(gl, block);
            }
        }

        for (Controller controller : controllers) {
            controller.draw(gl);
        }
        
        gl.glFlush();
    }

    @Override
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL gl = drawable.getGL();
        gl.glMatrixMode(GL_PROJECTION);
        GLU glu = new GLU();
        gl.glLoadIdentity();
        glu.gluOrtho2D(0, width, height, 0);
        gl.glMatrixMode(GL_MODELVIEW);
    }

    @Override
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {
        // Not used ATM
    }

    protected static float toDegrees(float radians) {
        return radians * 180.0f / (float) Math.PI;
    }

    public void addController(Controller c) {
        controllers.add(c);
    }
    
    public void removeController(Controller c) {
        controllers.remove(c);
    }

    
}
